package com.practice.datasource;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;

public class JDBC4DataSourceTemplate {
    private DataSource dataSource;

    public JDBC4DataSourceTemplate(DataSource dataSource){
        this.dataSource = dataSource;
    }

    public void excute(String sql){
        try (Connection connection = dataSource.getConnection();
             Statement statement = connection.createStatement()){
            statement.execute(sql);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public <T> T queryForObject(String sql, Object[] params, Class<T> clazz) throws SQLException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        //使用try-with-resource获得数据库连接并执行对应sql，便于资源的管理
        try(Connection connection = dataSource.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql)){
            //PreparedStatement是预编译的，这里设置对应占位符的参数
            for(int i = 0 ;i<params.length;i++){
                preparedStatement.setObject(i+1,params[i]);
            }
            //获得sql执行的结果
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next()){
                return mapRowToEntity(resultSet,clazz);
            }
        }
        return null;
    }

    //讲结果转为对应的实体类
    private <T> T mapRowToEntity(ResultSet resultSet, Class<T> clazz) throws SQLException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //利用反射获得对应实例
        T entity = clazz.getDeclaredConstructor().newInstance();
        //获取每一列
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();

        //遍历设置对应实例属性
        for(int i=1;i<=columnCount;i++){
            String columnName = metaData.getColumnName(i);
            String valueName = underlineToCamel(columnName);
            try {
                Field field = clazz.getDeclaredField(valueName);
                //System.out.println(field.getName());
                field.setAccessible(true);
                Object value = resultSet.getObject(columnName);
                field.set(entity,value);
            }catch (NoSuchFieldException | IllegalAccessException e){
                e.printStackTrace();
            }
        }

        return entity;
    }

    //下划线转驼峰
     private static String underlineToCamel(String underlineStr) {
        if (underlineStr == null || underlineStr.isEmpty()) {
            return underlineStr;
        }
        StringBuilder camelStr = new StringBuilder();
        boolean nextToUpper = false; // 是否将下一个字符转为大写

        for (char c : underlineStr.toCharArray()) {
            if (c == '_') {
                nextToUpper = true; // 下一个字符转为大写
            } else {
                camelStr.append(nextToUpper ? Character.toUpperCase(c) : c);
                nextToUpper = false; // 重置标志
            }
        }
        return camelStr.toString();
    }

    //驼峰转下划线
    private static String camelToUnderline(String camelStr) {
        if (camelStr == null || camelStr.isEmpty()) {
            return camelStr;
        }
        StringBuilder underlineStr = new StringBuilder();
        for (char c : camelStr.toCharArray()) {
            if (Character.isUpperCase(c)) {
                underlineStr.append('_').append(Character.toLowerCase(c)); // 大写转小写并添加下划线
            } else {
                underlineStr.append(c);
            }
        }
        return underlineStr.toString();
    }

}
